/*
 * Copyright 2007 - The JDPF Project Team (http://www.jdpf.org) 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */
package org.jdpf.core.kernel.execution;

import java.lang.reflect.InvocationTargetException;
import java.util.List;

import org.jdpf.core.kernel.elements.ITransition;
import org.jdpf.core.kernel.elements.Net;
import org.jdpf.core.kernel.elements.Place;
import org.jdpf.core.kernel.exceptions.CoreException;
import org.jdpf.core.kernel.exceptions.CoreExceptionsEnum;
import org.jdpf.core.kernel.logging.AbstractLoggingService;
import org.jdpf.core.plugins.blocks.AbstractTransitionPlugin;
import org.jdpf.core.plugins.parameters.Parameters;
import org.jdpf.core.plugins.parameters.PluginParameterValidator;

/*
 * This class is used for executing the net with a specific task
 * 
 * @author Paolo Ciccarese
 */
public class NetExecutor extends AbstractLoggingService {

	/**
	 * For pausing the process between transitions
	 */
	private boolean pause;	

	/**
	 * For recording the wiring validity
	 */
	private boolean valid;
	
	private Task task;
	private Net net;
	
	public NetExecutor(Task task, Net net) {
		this.task=task;
		this.net = net;
	}

	public void start() throws CoreException {
		for (ITransition transition : net.getAllTransitions()) {
			try {
				transition.getClass().getMethod("resetProcessStatus", null)
						.invoke(transition, null);
				transition.getClass().getMethod("setStart",
						new Class[] { boolean.class }).invoke(transition, true);
				transition.removeInputTokens();
			} catch (NoSuchMethodException e) {
				logger.error(this, "Method not found in transition: " + e.getMessage()); 
				throw new CoreException(CoreExceptionsEnum.MethodNotFound, "Method not found in transition: " + e.getMessage());
			} catch (InvocationTargetException e) {
				logger.error(this, "Reflection problem in transition: " + e.getTargetException().getMessage()); 
				throw new CoreException(CoreExceptionsEnum.MethodNotFound, "Reflection problem in transition: " + e.getTargetException().getMessage());
			} catch (Exception e) {
				logger.error(this, e.getMessage());
				throw new CoreException(CoreExceptionsEnum.TaskExecutionError, "Method not found in transition: " + e.getMessage());
			}
		}
	}
	
	public void process() throws Exception {
		for (ITransition transition : net.getAllTransitions()) {
			if (transition.isEnabled()) {
				transition.fire(task);
				if (!pause) {
					process();
				}
			}
		}
	}
	
	public void stop() {
		pause = false;
		for (ITransition transition : net.getAllTransitions()) {
			try {
				transition.getClass().getMethod("stop", null).invoke(
						transition, null);
				transition.getClass().getMethod("resetProcessStatus", null)
						.invoke(transition, null);
				if(taskLogging) logger.log(this, ((AbstractTransitionPlugin)transition).getPluginId(), "STOPPED");
			} catch (Exception e) {
				if(e.getMessage() != null) 
					logger.error(this, e.getMessage()); 
				else
					logger.error(this, e.getCause().getMessage()); 
				break;
			}
		}
	}
	
	public void checkParameters(Parameters param) throws CoreException {

		for (ITransition trans : net.getAllTransitions()) {
			String id = null;
			String pluginId = null;
			try {
				id = (String) trans.getClass().getMethod(
						"getAbstractTransitionId", null).invoke(trans, null);
				pluginId = (String) trans.getClass().getMethod("getPluginId",
						null).invoke(trans, null);
			} catch (Exception e) {
				logger.error(this, e.getMessage()); 
				break;
			}
			
			PluginParameterValidator mpv = new PluginParameterValidator(pluginId, id, Boolean.parseBoolean((String)param.getParameterValue(this.getClass().getName(), "TaskLogging")));
			mpv.checkParameter(param);
		}
	}
	
	public List<Place> getStartPlaces() throws CoreException {
		return net.getStartPlaces();
	}
	
	public String getNetName() {
		return net.getName();
	}
	
	public void setPause(boolean pause) {
		this.pause = pause;
	}

	public boolean isPaused() {
		return pause;
	}
	
	public Net getNet() {
		return net;
	}

	public boolean isValid() {
		return valid;
	}

	public void setValid(boolean valid) {
		this.valid = valid;
	}
}
